#pragma once

/**
 * Timer:计时器模块
 * 避免⼀个连接长时间不通信，但是也不关闭，空耗资源的情况，定时地将超时过期的连接释放
 * 两种高效管理定时器的容器：时间轮（TimeWheel）和时间堆（TimeHeap）
 * devem 使用时间轮来实现计时器，当刷新延迟时，采用智能指针来回收（也可以主动释放旧的任务 todo）
 */

#include "Channel.h"
#include "EventLoop.hpp"
#include "Logger.h"

#include <sys/timerfd.h>
#include <time.h>

#include <memory>
#include <vector>

namespace devem {

using TaskFunc = std::function<void()>;
using RealseFunc = std::function<void()>;

class TimerTask {
public:
    TimerTask(uint64_t id, uint64_t delay, TaskFunc task_func, RealseFunc realse_func)
        : id_(id), delay_(delay), task_func_(task_func), realse_func_(realse_func), canceled_(false) {}

    uint64_t DelayTime() { return delay_; }

    ~TimerTask() {
        if (canceled_ == false)
            task_func_();
        realse_func_();
    }
    void Cancel() { canceled_ = true; }

private:
    uint64_t id_;
    uint64_t delay_;
    bool canceled_;  // false-表示没有被取消， true-表示被取消
    TaskFunc task_func_;
    RealseFunc realse_func_;
};

typedef std::shared_ptr<TimerTask> SharedTask;
typedef std::weak_ptr<TimerTask> WeakTask;

class Timer {
public:
    void RemoveTimerTask(uint64_t id) {
        auto it = active_tasks_.find(id);
        if (it == active_tasks_.end())
            return;
        active_tasks_.erase(it);
    }

    void PushTimerTask(uint64_t id, uint64_t delay, TaskFunc task_func) {
        SharedTask newtask(new TimerTask(id, delay, task_func, std::bind(&Timer::RemoveTimerTask, this, id)));
        /*
            时间轮包含N个槽位，每个槽位上都有一个定时器链表。时间轮以恒定的速度顺时针转动，
            每转一步，表盘上的指针就指向下一个槽位。每次转动对应一个tick，它的周期为si，一个共有N个槽，所以它运转一周的时间是N*si。
            每个槽位都有一条定时器链表，同一条链表上的每个定时器都具有相同的特征：前后节点的定时时间相差N*si的整数倍。
            假如现在指针指向槽cs，我们要添加一个定时时间为ti的定时器，则该定时器将被插入槽ts(time slot)对应的链表中：
                ts = (cs + (ti / si)) % N
        */
        int solt = (tick_ + (delay / 1)) % capacity_;
        wheel_[solt].push_back(newtask);
        active_tasks_[id] = static_cast<WeakTask>(newtask);
    }

    // 刷新/延长时间轮的任务
    void RefreshTimerTask(uint64_t id) {
        auto it = active_tasks_.find(id);
        if (it == active_tasks_.end())
            return;
        // lock获取weak_ptr管理的对象对应的shared_ptr
        SharedTask shared_task = it->second.lock();
        int delay = shared_task->DelayTime();
        int solt = (tick_ + (delay / 1)) % capacity_;
        wheel_[solt].push_back(shared_task);
    }

    // 取消时间轮任务
    void CancelTimerTask(uint64_t id) {
        auto it = active_tasks_.find(id);
        if (it == active_tasks_.end())
            return;
        SharedTask shared_task = it->second.lock();
        if (shared_task)
            shared_task->Cancel();
    }

private:
    int CreateTimerFd();

    void RunOnTimeTask() {
        tick_ = (tick_ + 1) % capacity_;
        wheel_[tick_].clear();
    }

    void ReadTimerFd() {
        uint64_t times;
        ssize_t sz = read(timer_fd_, &times, sizeof(uint64_t));
        if (sz < 0) {
            LOG_WARN("readfd is %d, read fail.", timer_fd_);
            return;
        }
        for (int i = 0; i < times; i++) {
            RunOnTimeTask();
        }
    }

public:
    Timer(EventLoop* loop, int tick = 0, int capacity = 60)
        : tick_(tick),
          capacity_(capacity),
          wheel_(capacity_),
          loop_(loop),
          timer_fd_(CreateTimerFd()),
          timer_channel_(new Channel(timer_fd_, loop_)) {
        timer_channel_->EnableRead();
        timer_channel_->SetReadCallBack(std::bind(&Timer::ReadTimerFd, this));
    }

private:
    int tick_;                                    // 当前的秒针，走到哪执行哪的任务
    int capacity_;                                // 最大延迟时间
    std::vector<std::vector<SharedTask>> wheel_;  // 任务轮盘
    EventLoop* loop_;
    int timer_fd_;
    std::unique_ptr<Channel> timer_channel_;
    std::unordered_map<uint64_t, WeakTask> active_tasks_;
};

}  // namespace devem